﻿using System.Collections.Generic;

namespace ChengNet.StrongCaml.Node
{
    /// <summary>A single filter <see cref="Condition"/></summary>
    public abstract class Comparison : Condition
    {
        /// <summary>Constructor with one field</summary>
        protected Comparison(FieldRef fieldRef) : base(fieldRef) { }

        /// <summary>Constructor for ValueType.Boolean values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        /// <summary>Constructor for ValueType.Integer values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { if (value.Child is UserID) fieldRef.LookupId = true; }
        /// <summary>Constructor for ValueType.Lookup values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { fieldRef.LookupId = true; }
        /// <summary>Constructor for ValueType.Text values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        /// <summary>Constructor for ValueType.Note values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        /// <summary>Constructor for ValueType.DateTime values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
        /// <summary>Constructor for ValueType.User values</summary>
        protected Comparison(FieldRef fieldRef, Value<ValueType.User> value) : base(fieldRef, value) { fieldRef.LookupId = true; }
    }

    // filter based on user membership
    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Membership : Comparison
    {
        internal Membership(FieldRef fieldRef, MembershipType type)
            : base(fieldRef) {
            Attributes = new Dictionary<string, string>();

            switch (type) {
                case MembershipType.SPWebAllUsers:
                    Attributes["Type"] = "SPWeb.AllUsers"; break;
                case MembershipType.SPGroup:
                    Attributes["Type"] = "SPGroup"; break;
                case MembershipType.SPWebGroups:
                    Attributes["Type"] = "SPWeb.Groups"; break;
                case MembershipType.CurrentUserGroups:
                    Attributes["Type"] = "CurrentUserGroups"; break;
                case MembershipType.SPWebUsers:
                    Attributes["Type"] = "SPWeb.Users"; break;
            }
        }
    }

    // comparisons
    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class IsNull : Comparison { internal IsNull(FieldRef fieldRef) : base(fieldRef) { } }
    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class IsNotNull : Comparison { internal IsNotNull(FieldRef fieldRef) : base(fieldRef) { } }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Eq : Comparison
    {
        internal Eq(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        internal Eq(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { }
        internal Eq(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { }
        internal Eq(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Eq(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        internal Eq(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
        internal Eq(FieldRef fieldRef, Value<ValueType.User> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Neq : Comparison
    {
        internal Neq(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        internal Neq(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { }
        internal Neq(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { }
        internal Neq(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Neq(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        internal Neq(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
        internal Neq(FieldRef fieldRef, Value<ValueType.User> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Lt : Comparison
    {
        internal Lt(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        internal Lt(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { }
        internal Lt(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { }
        internal Lt(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Lt(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        internal Lt(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Gt : Comparison
    {
        internal Gt(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        internal Gt(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { }
        internal Gt(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { }
        internal Gt(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Gt(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        internal Gt(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Leq : Comparison
    {
        internal Leq(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        internal Leq(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { }
        internal Leq(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { }
        internal Leq(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Leq(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        internal Leq(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Geq : Comparison
    {
        internal Geq(FieldRef fieldRef, Value<ValueType.Boolean> value) : base(fieldRef, value) { }
        internal Geq(FieldRef fieldRef, Value<ValueType.Integer> value) : base(fieldRef, value) { }
        internal Geq(FieldRef fieldRef, Value<ValueType.Lookup> value) : base(fieldRef, value) { }
        internal Geq(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Geq(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
        internal Geq(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class Contains : Comparison
    {
        internal Contains(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal Contains(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class BeginsWith : Comparison
    {
        internal BeginsWith(FieldRef fieldRef, Value<ValueType.Text> value) : base(fieldRef, value) { }
        internal BeginsWith(FieldRef fieldRef, Value<ValueType.Note> value) : base(fieldRef, value) { }
    }

    /// <summary>Do not instantiate directly. Use <see cref="Caml"/>.</summary>
    public class DateRangesOverlap : Comparison
    {
        internal DateRangesOverlap(FieldRef fieldRef, Value<ValueType.DateTime> value) : base(fieldRef, value) { }
    }
}
